#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
智谱视觉大模型分析器模块
负责视频关键帧提取和智谱视觉大模型API调用
"""

import os
import json
import time
import base64
import requests
import cv2
import numpy as np
from typing import Dict, Any, List, Optional, Tuple
from datetime import datetime
from dotenv import load_dotenv

# 导入错误处理模块
from .error_handler import ZhipuApiErrorHandler, RetryStrategy

# 加载环境变量
load_dotenv()


class ZhipuVisionAnalyzer:
    """
    智谱视觉大模型分析器
    使用智谱AI的视觉大模型对视频关键帧进行分析
    """
    
    def __init__(self):
        """
        初始化智谱视觉大模型分析器
        """
        # 从环境变量获取API密钥
        self.api_key = os.getenv('ZHIPU_API_KEY')
        
        if not self.api_key:
            raise ValueError("未找到智谱AI API密钥，请在.env文件中设置ZHIPU_API_KEY")
        
        # 智谱AI API配置
        self.api_url = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
        self.model_name = "glm-4v"
        
        # 视频处理配置
        self.max_frames = 5  # 最多提取的关键帧数量
        self.frame_interval = 3  # 帧间隔（秒）
        
        # 提示词模板
        self.prompt_template = self._load_prompt_template()
        
        # 初始化错误处理器
        retry_strategy = RetryStrategy(
            max_retries=3,      # 最大重试次数
            base_delay=2.0,     # 基础延迟时间（秒）
            max_delay=30.0      # 最大延迟时间（秒）
        )
        self.error_handler = ZhipuApiErrorHandler(retry_strategy=retry_strategy)
    
    def _load_prompt_template(self) -> str:
        """
        加载提示词模板
        
        Returns:
            str: 提示词模板
        """
        return """
# 视频内容编码分析任务

## 任务描述
你是一个专业的视频内容分析专家，需要对视频内容进行多维度编码分析。请基于视频的关键帧内容，按照以下分类标准进行分析判断。

## 视频基本信息
- 视频ID: {video_id}
- 分析时间: {current_time}

## 编码类目分析标准

### 1. 场景设定分析
请判断视频的主要场景类型：
- 校园场景：出现校园、学校、大学、教室、宿舍、图书馆、教学楼、操场等
- 生活场景：出现生活、家庭、日常、家居、厨房、起居、生活记录等  
- 文化场景：出现文化、传统、节日、艺术、博物馆、文化遗产、习俗等
- 社交场景：出现社交、朋友、聚会、约会、社区、团体、互动等
- 其他：其他场景、未分类、特殊场景、非常见场景

### 2. 声音素材分析
请判断视频的主要声音类型：
- 博主原声：博主原声、人声、讲解、原音、录音、语音
- 背景音乐：背景音乐、BGM、音乐、配乐、歌曲、旋律
- 音效素材：音效、效果音、声音效果、特效音、环境音
- 文本转语音：文本转语音、TTS、语音合成、合成语音、自动朗读
- 其他：其他声音、音源其他、混合音轨、未分类声音

### 3. 主题类型分析
请判断视频的主要主题：
- 学业分享：学业、学习、考试、教育、分享经验、课程、学习方法
- 生活实用：生活实用、技巧、日常技巧、家务、生活指南、实用建议
- 文化体验：文化体验、传统、习俗、文化分享、文化探索、文化遗产
- 情感表达：情感、心情、感受、表达、情感分享、心理
- 身份认同：身份、认同、自我、群体、身份表达、社会角色
- 娱乐创意：娱乐、创意、搞笑、有趣、幽默、创意内容、娱乐节目
- 价值输出：价值、观点、输出、理念、价值观、思想表达

### 4. 视频情感倾向分析
请判断视频的情感倾向：
- 积极正向：积极、正向、乐观、快乐、喜悦、鼓舞、正能量
- 消极负向：消极、负向、悲观、悲伤、愤怒、失望、负面
- 中性客观：中性、客观、中立、事实、平静、无偏见、理性

### 5. 话题标签分析
请判断视频是否关联或创建话题：
- 关联或创建话题：话题、标签、创建话题、关联话题、热门话题、主题标签
- 未关联或创建话题：无话题、未关联、无标签、未创建、空白标签、无主题

### 6. 作者昵称类型分析
请基于可见信息判断作者昵称类型：
- 个人姓名：个人姓名、真名、全名、实名、本名
- 自身状态：自身状态、昵称、身份描述、状态描述、角色名、匿名标识
- 其他：其他昵称、匿名、未指定、特殊昵称、无昵称

### 7. 作者简介内容分析
请基于可见信息判断作者简介类型：
- 经历介绍：经历、简介、背景、个人经历、履历、人生故事
- 个性签名：个性签名、签名、座右铭、格言、个性说明、标语
- 业务咨询：业务咨询、合作、联系、商务、服务、商业合作
- 其他：其他简介、无简介、未填写、空白简介、自定义内容

## 分析要求
1. 对每个类目选择最合适的选项
2. 为每个判断提供置信度评分（0-100%）
3. 简要说明分析依据和关键观察点
4. 如果信息不足无法判断，请标记为"待AI推断"
5. 重点关注视觉元素：环境、人物、物体、文字、色彩、构图等

## 输出格式要求
请严格按照以下JSON格式输出分析结果：

```json
{{
  "video_id": "{video_id}",
  "analysis_time": "{current_time}",
  "scene_setting": {{
    "option": "选项名称",
    "confidence": 85,
    "reasoning": "分析依据说明"
  }},
  "audio_material": {{
    "option": "选项名称", 
    "confidence": 90,
    "reasoning": "分析依据说明"
  }},
  "theme_type": {{
    "option": "选项名称",
    "confidence": 88, 
    "reasoning": "分析依据说明"
  }},
  "emotional_tendency": {{
    "option": "选项名称",
    "confidence": 80,
    "reasoning": "分析依据说明"
  }},
  "topic_tags": {{
    "option": "选项名称",
    "confidence": 75,
    "reasoning": "分析依据说明"
  }},
  "author_nickname_type": {{
    "option": "选项名称", 
    "confidence": 70,
    "reasoning": "分析依据说明"
  }},
  "author_intro_content": {{
    "option": "选项名称",
    "confidence": 65,
    "reasoning": "分析依据说明"
  }},
  "overall_confidence": 78,
  "analysis_notes": "总体分析备注和建议"
}}
```

## 注意事项
- 基于视频画面内容进行客观分析
- 避免过度推断，以可见证据为准
- 对不确定的内容保持谨慎，标记为低置信度
- 优先选择最匹配的选项，不要创建新选项
        """
    
    def extract_key_frames(self, video_path: str) -> List[bytes]:
        """
        从视频中提取关键帧
        
        Args:
            video_path: 视频文件路径
            
        Returns:
            List[bytes]: 关键帧列表（base64编码的图像数据）
        """
        if not os.path.exists(video_path):
            raise FileNotFoundError(f"视频文件不存在: {video_path}")
        
        # 打开视频文件
        cap = cv2.VideoCapture(video_path)
        
        if not cap.isOpened():
            raise ValueError(f"无法打开视频文件: {video_path}")
        
        # 获取视频信息
        fps = cap.get(cv2.CAP_PROP_FPS)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        duration = total_frames / fps if fps > 0 else 0
        
        print(f"视频信息: {os.path.basename(video_path)}")
        print(f"  时长: {duration:.2f}秒, 帧率: {fps:.2f}fps, 总帧数: {total_frames}")
        
        # 计算采样间隔
        frame_interval_frames = int(fps * self.frame_interval)
        if frame_interval_frames < 1:
            frame_interval_frames = 1
        
        # 采样的帧位置
        sample_positions = []
        if duration <= self.frame_interval * (self.max_frames - 1):
            # 视频较短，采样所有可能的帧
            for i in range(0, total_frames, frame_interval_frames):
                sample_positions.append(i)
        else:
            # 视频较长，均匀采样
            step = total_frames / (self.max_frames + 1)
            for i in range(1, self.max_frames + 1):
                sample_positions.append(int(step * i))
        
        # 确保采样帧数不超过最大限制
        sample_positions = sample_positions[:self.max_frames]
        
        # 提取关键帧
        key_frames = []
        
        for frame_idx in sample_positions:
            # 设置帧位置
            cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
            
            # 读取帧
            ret, frame = cap.read()
            if ret:
                # 转换为base64
                _, buffer = cv2.imencode('.jpg', frame)
                frame_bytes = buffer.tobytes()
                key_frames.append(frame_bytes)
                
                print(f"  提取帧: {frame_idx}/{total_frames}")
        
        # 释放资源
        cap.release()
        
        print(f"成功提取 {len(key_frames)} 个关键帧")
        
        return key_frames
    
    def analyze_video(self, video_path: str, video_id: str) -> Dict[str, Any]:
        """
        分析视频内容
        
        Args:
            video_path: 视频文件路径
            video_id: 视频ID
            
        Returns:
            Dict[str, Any]: 分析结果
        """
        try:
            # 提取关键帧
            key_frames = self.extract_key_frames(video_path)
            
            if not key_frames:
                error_msg = "无法从视频中提取关键帧"
                print(f"错误: {error_msg}")
                return {
                    "status": "error",
                    "error_message": error_msg,
                    "video_id": video_id,
                    "analysis_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                }
            
            # 生成分析提示词
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            prompt = self.prompt_template.format(
                video_id=video_id,
                current_time=current_time
            )
            
            # 调用智谱视觉大模型
            analysis_result = self._call_zhipu_api(prompt, key_frames)
            
            # 验证和处理结果
            processed_result = self._process_api_response(analysis_result)
            
            return processed_result
            
        except Exception as e:
            # 捕获所有其他异常
            error_msg = f"视频分析过程中发生错误: {str(e)}"
            print(f"错误: {error_msg}")
            return {
                "status": "error",
                "error_message": error_msg,
                "video_id": video_id,
                "analysis_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
    
    def _call_zhipu_api(self, prompt: str, key_frames: List[bytes]) -> Dict[str, Any]:
        """
        调用智谱视觉大模型API
        
        Args:
            prompt: 提示词
            key_frames: 关键帧列表
            
        Returns:
            Dict[str, Any]: API响应结果
        """
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }
        
        # 准备消息
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt}
                ]
            }
        ]
        
        # 添加图像数据
        for frame_bytes in key_frames:
            # 编码为base64
            base64_image = base64.b64encode(frame_bytes).decode('utf-8')
            
            messages[0]["content"].append({
                "type": "image",
                "image": base64_image
            })
        
        # 准备请求数据
        data = {
            "model": self.model_name,
            "messages": messages,
            "temperature": 0.3,
            "max_tokens": 2000
        }
        
        # 定义实际的API调用函数
        def _api_request():
            """内部API请求函数，供错误处理器调用"""
            print(f"调用智谱视觉大模型API (模型: {self.model_name})...")
            
            # 发送请求
            response = requests.post(
                self.api_url,
                headers=headers,
                data=json.dumps(data),
                timeout=300  # 5分钟超时
            )
            
            # 检查响应状态
            response.raise_for_status()
            
            # 解析响应
            result = response.json()
            
            # 获取回复内容
            if "choices" in result and result["choices"] and "message" in result["choices"][0]:
                content = result["choices"][0]["message"]["content"]
                print(f"API调用成功，返回内容长度: {len(content)}字符")
                return {"success": True, "content": content}
            else:
                error_msg = "无效响应格式"
                print(f"API调用失败: {error_msg}")
                return {"success": False, "error": error_msg}
        
        # 使用错误处理器执行API调用
        return self.error_handler.handle_api_call(_api_request)
    
    def _process_api_response(self, api_result: Dict[str, Any]) -> Dict[str, Any]:
        """
        处理API响应结果
        
        Args:
            api_result: API调用结果
            
        Returns:
            Dict[str, Any]: 处理后的分析结果
        """
        if not api_result.get("success", False):
            return {
                "status": "error",
                "error_message": api_result.get("error", "API调用失败"),
                "video_id": "",
                "analysis_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
        
        # 获取内容
        content = api_result.get("content", "")
        
        try:
            # 尝试提取JSON部分
            # 查找 ```json 和 ``` 标记
            json_start = content.find("```json")
            json_end = content.find("```", json_start + 7)
            
            if json_start != -1 and json_end != -1:
                json_content = content[json_start + 7:json_end].strip()
                result = json.loads(json_content)
            else:
                # 尝试直接解析内容
                result = json.loads(content)
            
            # 添加状态信息
            result["status"] = "success"
            
            # 计算总体置信度（如果未提供）
            if "overall_confidence" not in result:
                confidences = []
                categories = [
                    "scene_setting", "audio_material", "theme_type",
                    "emotional_tendency", "topic_tags", 
                    "author_nickname_type", "author_intro_content"
                ]
                
                for category in categories:
                    if category in result and isinstance(result[category], dict):
                        conf = result[category].get("confidence", 0)
                        if conf > 0:  # 只考虑有效的置信度
                            confidences.append(conf)
                
                if confidences:
                    result["overall_confidence"] = int(sum(confidences) / len(confidences))
                else:
                    result["overall_confidence"] = 0
            
            # 标记需要补充推断的字段
            result["fields_to_supplement"] = self._identify_fields_to_supplement(result)
            
            print("响应结果处理成功")
            return result
            
        except json.JSONDecodeError as e:
            print(f"JSON解析失败: {str(e)}")
            return {
                "status": "error",
                "error_message": f"JSON解析失败: {str(e)}",
                "raw_content": content,
                "video_id": "",
                "analysis_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
    
    def _identify_fields_to_supplement(self, result: Dict[str, Any]) -> List[str]:
        """
        识别需要补充推断的字段
        
        Args:
            result: 分析结果
            
        Returns:
            List[str]: 需要补充的字段列表
        """
        fields_to_supplement = []
        
        categories = {
            "scene_setting": "场景设定",
            "audio_material": "声音素材",
            "theme_type": "主题类型",
            "emotional_tendency": "视频情感倾向",
            "topic_tags": "话题标签",
            "author_nickname_type": "作者昵称类型",
            "author_intro_content": "作者简介内容"
        }
        
        for field_key, field_name in categories.items():
            if field_key in result:
                field_data = result[field_key]
                
                # 检查是否为字典
                if isinstance(field_data, dict):
                    # 检查置信度
                    confidence = field_data.get("confidence", 0)
                    if confidence < 70:
                        fields_to_supplement.append(field_name)
                    
                    # 检查是否标记为待推断
                    option = field_data.get("option", "")
                    if "待AI推断" in option or "未确定" in option:
                        fields_to_supplement.append(field_name)
                else:
                    # 如果不是字典格式，也需要补充
                    fields_to_supplement.append(field_name)
            else:
                # 缺失的字段需要补充
                fields_to_supplement.append(field_name)
        
        return fields_to_supplement
    
    def export_analysis_report(self, result: Dict[str, Any], output_path: str = None) -> str:
        """
        导出分析报告
        
        Args:
            result: 分析结果
            output_path: 输出路径
            
        Returns:
            str: 报告内容
        """
        # 生成报告内容
        report = []
        report.append("视频编码分析报告")
        report.append("====================")
        report.append("")
        
        report.append("【基础信息】")
        report.append(f"视频ID: {result.get('video_id', '')}")
        report.append(f"分析时间: {result.get('analysis_time', '')}")
        report.append(f"分析模型: 智谱视觉大模型")
        report.append(f"分析状态: {result.get('status', 'unknown')}")
        report.append("")
        
        report.append("【编码类目分析结果】")
        categories = {
            "scene_setting": "1. 场景设定",
            "audio_material": "2. 声音素材",
            "theme_type": "3. 主题类型",
            "emotional_tendency": "4. 视频情感倾向",
            "topic_tags": "5. 话题标签",
            "author_nickname_type": "6. 作者昵称类型",
            "author_intro_content": "7. 作者简介内容"
        }
        
        for field_key, field_title in categories.items():
            if field_key in result and isinstance(result[field_key], dict):
                option = result[field_key].get("option", "未确定")
                confidence = result[field_key].get("confidence", 0)
                report.append(f"{field_title}: {option}")
        report.append("")
        
        report.append("【分析详情】")
        for field_key, field_title in categories.items():
            if field_key in result and isinstance(result[field_key], dict):
                reasoning = result[field_key].get("reasoning", "无")
                field_name = field_title.split('. ')[1]  # 提取字段名称
                report.append(f"- {field_name}分析依据: {reasoning}")
        report.append("")
        
        report.append("【待补充字段标记】")
        fields_to_supplement = result.get("fields_to_supplement", [])
        if fields_to_supplement:
            report.append("以下字段需要进一步分析补充:")
            for field in fields_to_supplement:
                report.append(f"- {field}")
        else:
            report.append("所有字段分析完整，无需补充")
        report.append("")
        
        report.append("【分析置信度】")
        report.append(f"总体置信度: {result.get('overall_confidence', 0)}%")
        report.append("各字段置信度:")
        for field_key, field_title in categories.items():
            if field_key in result and isinstance(result[field_key], dict):
                confidence = result[field_key].get("confidence", 0)
                field_name = field_title.split('. ')[1]  # 提取字段名称
                report.append(f"- {field_name}: {confidence}%")
        report.append("")
        
        report.append("【分析备注】")
        report.append(result.get("analysis_notes", "无"))
        
        # 生成报告文本
        report_text = "\n".join(report)
        
        # 如果指定了输出路径，保存到文件
        if output_path:
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(report_text)
            print(f"分析报告已保存到: {output_path}")
        
        return report_text


# 使用示例
if __name__ == '__main__':
    try:
        # 创建分析器实例
        analyzer = ZhipuVisionAnalyzer()
        
        # 示例视频路径（需要替换为实际路径）
        # video_path = "../data/MP4/sample_video.mp4"
        # video_id = "sample_video_001"
        
        # 如果有示例视频，可以取消注释以下代码进行测试
        # result = analyzer.analyze_video(video_path, video_id)
        # 
        # # 打印结果
        # print("\n分析结果摘要:")
        # print(f"视频ID: {result.get('video_id')}")
        # print(f"分析状态: {result.get('status')}")
        # print(f"总体置信度: {result.get('overall_confidence')}%")
        # print(f"需要补充的字段: {', '.join(result.get('fields_to_supplement', []))}")
        # 
        # # 导出报告
        # report_path = f"../reports/analysis_report_{video_id}.txt"
        # analyzer.export_analysis_report(result, report_path)
        
        print("智谱视觉大模型分析器初始化成功!")
        print("请在实际使用时，提供有效的视频路径进行分析。")
        
    except Exception as e:
        print(f"初始化失败: {str(e)}")